/**
* This file defines functions in utils.h
*/
#define _XOPEN_SOURCE // For crypt()

#include "utils.h"

/**
* This function sends all the buffer with max len to sock
* @param sock Sockfd to be sent to
* @param buf Contains data to be sent
* @len Maximum size of buf to send
*/
int sendall(const int sock, const char *buf, const size_t len)
{
    size_t tosend = len;
    while (tosend > 0)
    {
	// (sockfd to send to, buffer which contains data, amount of info, flags)
	ssize_t bytes = send(sock, buf, tosend, 0);
	if (bytes <= 0)
	    break; // send() was not successful, so stop.
	tosend -= (size_t) bytes;
	buf += bytes;
    };
    return tosend == 0 ? 0 : -1;
}

/**
*  This function receives all data from sock
* @param sock The sockfd to be received from
* @param buf The buffer to store data received
* @param buflen Maximum size to be received
*/
int recvline(const int sock, char *buf, const size_t buflen)
{
    // status returns -1 if not successful in receiving any data
    //		      0 if new line received
    int status = 0; // Return status.
    size_t bufleft = buflen;
    // while there is space in the buffer to receive
    while (bufleft > 1) // and no errors and no newline received
    {
	// Read one byte from socket
	// (sockfd to read from, buf to receive data, receive 1 data, flags)
	ssize_t bytes = recv(sock, buf, 1, 0);
	if (bytes <= 0)
	{
	    // recv() was not successful, so stop.
	    status = -1;
	    break;
	}
	else if (*buf == '\n')
	{
	// Found end of line, so stop.
	*buf = 0; // Replace end of line with a null terminator.
	status = 0;
	break;
	}
	else
	{
	    // Keep going.
	    bufleft -= 1; // decrease space left in buffer
	    buf += 1; // increment position in buffer to store data
	}
    }
    *buf = 0; // add null terminator in case it's not already there.
    return status;
}

/**
* This function processes one line from the config file
* and stores its value into config_params
*/
int process_config_line(char *line, struct config_params *params)
{
    // Ignore comments.
    if (line[0] == CONFIG_COMMENT_CHAR) // defined in util.h
	return 0;
    // Extract config parameter name and value.
    char name[MAX_CONFIG_LINE_LEN];
    char value[MAX_CONFIG_LINE_LEN];
    char extra[MAX_CONFIG_LINE_LEN];
    // Scan the str line, for the first 2 strings and store it into name and value
    // returns number of items in argument list successfully filled
    int items = sscanf(line, "%s %s %s\n", name, value, extra);
    // Line wasn't as expected.
    if (items != 2)
    {
printf("Items is %d\n and line is:\n%s \n", items, line);
	// it returns -1 when it sees an empty line
    // TODO: Print an error message here about config file
	return -1;
    }

printf("Line is %swhile item is %d\n", line, items);
    // Process this line.
    if (strcmp(name, "server_host") == 0) // if exactly the same str
    {
	// Copy to server_host the valu
	strncpy(params->server_host, value, sizeof params->server_host);
    }
    else if (strcmp(name, "server_port") == 0)
    {
	// Copy to server port the value in int
	params->server_port = atoi(value);
    }
    else if (strcmp(name, "username") == 0)
    {
	// Copy to username the value in str
	strncpy(params->username, value, sizeof params->username);
    }
    else if (strcmp(name, "password") == 0)
    {
	// Copy to password the value in str
	strncpy(params->password, value, sizeof params->password);
    }
//    else if (strcmp(name, "data_directory") == 0)
//    {
//	strncpy(params->data_directory, value, sizeof params->data_directory);
//    }
// Ignore unknown configuration parameters
    else
    {
	// TODO: Print Error Message
	// Ignore unknown config parameters.
    }
        return 0;
}

/**
* This function reads the configuration file and stores it into config_params struct
* @note: Uses process_config_line()
* @return 0 if successful, -1 otherwise
*/
int read_config(const char *config_file, struct config_params *params)
{
    int error_occurred = 0;
    // Open file for reading.
    FILE *file = fopen(config_file, "r");
    if (file == NULL)
	error_occurred = 1;
    // Process the config file.
    while (!error_occurred && !feof(file))
    {
	// Read a line from the file.
	char line[MAX_CONFIG_LINE_LEN];
	// reads from file (line-1) characters or until newline is found
	// and stores into line. Automatically handles null terminates
	// and returns pointer to line on success
	char *l = fgets(line, sizeof line, file);
	// Process the line.
	if (l == line) // If success getting this line, do process_config_line
{
	printf("Line exists and is %s\n", line);
	    process_config_line(line, params);
}
	else if (!feof(file))
	    error_occurred = 1;
    }
    return error_occurred ? -1 : 0;
}

/**
* This function logs a message to a file
* @param file The file to be logged to
* @param message The message to log
*/
void logger(FILE *file, char *message)
{
    if (file == NULL) // No logging needed
    {
	return;
    }
    fprintf(file,"%s",message);
    fflush(file);
}

/**
* This function generates an encrypted password and returns by pointer
* @param passwd String where the encrypted password is stored
* @note: Uses UNIX's function crypt()
*/
char *generate_encrypted_password(const char *passwd, const char *salt)
{
    if(salt != NULL)
	return crypt(passwd, salt);
    else
	return crypt(passwd, DEFAULT_CRYPT_SALT);
}
